#pragma once
#ifndef OBR_RECORDS_H
#define OBR_RECORDS_H

#include "DScommon.h"

namespace OBR
{
/**
 * @brief SBT record template
 *
 * @tparam T
 */
template <typename T> struct Record
{
    __align__(OPTIX_SBT_RECORD_ALIGNMENT) char header[OPTIX_SBT_RECORD_HEADER_SIZE];
    T data;
};

typedef struct EmptyData
{
} EmptyData;

typedef struct RaygenData
{
    int med_id = -1;
    uint med_instance_id;
    /**
     * @brief points to an background data
     *
     * @attention this pointer should be converted to (XXXCameraData *) in shader
     */
    CUdeviceptr camera_payload;
} RaygenData;

typedef struct MissData
{
    /**
     * @brief points to an background data
     *
     * @attention this pointer should be converted to (XXXBackgroundData *) in shader
     */
    CUdeviceptr background_payload;
} MissData;

typedef struct HitData
{
    // points to mesh callable id & corresponding mesh data
    int mesh_id, mesh_instance_id;
    // points to material callable id & corresponding material data
    int mat_id = -1;
    int mat_instance_id;
    // points to light callable id & corresponding material data
    int light_id = -1;
    int light_instance_id;
    // points to to sided medium callable id & corresponding medium data
    int med_id_inside = -1, med_id_outside = -1;
    int med_instance_id_inside, med_instance_id_outside;

    /**
     * @brief points to an per-GAS instance of mesh data
     *
     * @attention this pointer should be converted to (XXXMeshData *) in shader
     */
    CUdeviceptr hit_payload;
    /**
     * @brief number of instances of this type of GAS
     *
     */
    int n_instances;
} HitData;

typedef struct CallableData
{
    /**
     * @brief points to an per-material / light / mesh instance of material data
     *
     * @attention this pointer should be converted to (XXXMaterialData *) in shader
     */
    CUdeviceptr callable_payload;
    /**
     * @brief number of instances of this type of callable
     *
     */
    int n_instances;
} CallableData;

typedef Record<RaygenData> RaygenRecord;
typedef Record<HitData> HitRecord;
typedef Record<MissData> MissRecord;
typedef Record<CallableData> CallableRecord;

} // namespace OBR

#endif